<?php

namespace youmbe\phpword\widgets;

use Yii;
use yii\base\Arrayable;
use yii\base\InvalidConfigException;
use yii\base\Model;
use yii\helpers\ArrayHelper;
use yii\helpers\Inflector;
use PhpOffice\PhpWord\Style\TablePosition;
use PhpOffice\PhpWord\SimpleType\JcTable;
use PhpOffice\PhpWord\SimpleType\TblWidth as TblWidthSimpleType;
use PhpOffice\PhpWord\Shared\Converter;
use PhpOffice\PhpWord\Style\Table as TableStyle;
use PhpOffice\PhpWord\ComplexType\TblWidth;

/**
 * DetailView displays the detail of a single word data [[model]].
 *
 * @author emhome <emhome@163.com>
 * @since 1.0
 */
abstract class BaseTableView extends \youmbe\phpword\base\Widget {

    /**
     * @var array the HTML attributes for the container tag of this widget. The `tag` option specifies
     * what container tag should be used. It defaults to `table` if not set.
     * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered.
     */
    public $options = [
        'width' => 100,
        'position' => false,
    ];

    /**
     * @var array the HTML attributes for the grid table element.
     * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered.
     */
    public $tableOptions = [
        'width' => 100,
        'position' => false,
        'cellMargin' => 5,
    ];

    /**
     * @var array the HTML attributes for the grid table element.
     * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered.
     */
    public $rowOptions = [];

    /**
     * @var string default `pct`
     * @see TblWidthSimpleType constants.
     */
    public $unit = TblWidthSimpleType::PERCENT;

    /**
     * @var \PhpOffice\PhpWord\Element\Table
     */
    public $layout;

    /**
     * @var int
     */
    public $break = 1;

    /**
     * @var array|null 标签选项
     */
    public $captionOptions;

    /**
     * @var array|null 内容选项
     */
    public $contentOptions;

    /**
     * @var number|null 行高度
     */
    public $rowHeight;

    /**
     * @var array|string|null 行样式
     */
    public $rowStyle;

    /**
     * @var array|string|null 首行样式
     */
    public $firstRowStyle = [
        //'bgColor' => 'ff6600',
        'cellMarginBottom' => 50,
        'cellSpacing' => 0,
    ];

    /**
     * @var array|string|null 单元格样式
     */
    public $cellStyle = [
        'valign' => 'center',
        'borderColor' => '9966CC',
        'borderSize' => 2,
        'unit' => TblWidthSimpleType::PERCENT,
    ];

    /**
     * Initializes the detail view.
     * This method will initialize required property values.
     */
    public function init() {
        parent::init();
        if ($this->section === null) {
            throw new InvalidConfigException('Please specify the "section" property.');
        }
    }

    /**
     * Renders the detail view.
     * This is the main entry of the whole detail view rendering.
     */
    public function run() {
        $this->layout = $this->section->addTable($this->getTableStyle());
        $this->renderLayout();
        if ($this->break) {
            $this->section->addTextBreak(intval($this->break));
        }
    }

    /**
     * Renders the table.
     * This is the main entry of the whole detail view rendering.
     */
    abstract public function renderLayout();

    /**
     * 
     * @param \PhpOffice\PhpWord\Element\Row $row
     * @param type $value
     * @param type $options
     */
    public function renderCell($row, $value, $options = []) {
        $cellStyle = ArrayHelper::getValue($options, 'cellStyle', []);
        $unit = ArrayHelper::getValue($options, 'cellStyle.unit') ?: $this->unit;
        $cellWidth = $this->formatUnitWidth(ArrayHelper::getValue($options, 'width', 100), $unit);
        $fontStyle = ArrayHelper::getValue($options, 'fontStyle', $this->fontStyle);
        $paragraphStyle = ArrayHelper::getValue($options, 'paragraphStyle', $this->paragraphStyle);
        $align = ArrayHelper::getValue($options, 'align');
        if ($align) {
            if (is_null($paragraphStyle)) {
                $paragraphStyle = [];
            }
            $paragraphStyle['alignment'] = $align;
        }
        $tempCellStyle = ArrayHelper::merge($this->cellStyle, $cellStyle);
        $row->addCell($cellWidth, $tempCellStyle)->addText($value, $fontStyle, $paragraphStyle);
    }

    /**
     * Renders the detail view.
     * This is the main entry of the whole detail view rendering.
     * @return array|null Description
     */
    public function getPositionStyle($name) {
        if ($name === 'absolute') {
            return [
                'vertAnchor' => TablePosition::VANCHOR_PAGE,
                'horzAnchor' => TablePosition::HANCHOR_PAGE,
                'tblpXSpec' => TablePosition::XALIGN_CENTER,
                'tblpYSpec' => TablePosition::YALIGN_CENTER,
            ];
        }
        return null;
    }

    /**
     * Format the width value to unit value.
     * @param number|null $value
     * @param string|null $unit
     * @return number|null Description
     */
    public function formatUnitWidth($value, $unit = null) {
        if (!is_numeric($value)) {
            return null;
        }
        if (!$unit) {
            $unit = $this->unit;
        }
        if ($unit == TblWidthSimpleType::PERCENT) {
            $value *= 50;
        } elseif ($unit == TblWidthSimpleType::TWIP) {
            $value = Converter::pointToTwip($value);
        }
        return $value;
    }

    /**
     * Renders the detail view.
     * This is the main entry of the whole detail view rendering.
     * @return array|null Description
     */
    public function getTableStyle() {
        $width = ArrayHelper::getValue($this->tableOptions, 'width') ?: 100;
        $unit = ArrayHelper::getValue($this->tableOptions, 'unit', $this->unit);
        $tableWidth = $this->formatUnitWidth($width, $unit);
        $tableStyle = ArrayHelper::getValue($this->tableOptions, 'tableStyle');
        if (!empty($tableStyle)) {
            return $tableStyle;
        }
        $position = ArrayHelper::getValue($this->tableOptions, 'position');
        $cellMargin = ArrayHelper::getValue($this->tableOptions, 'cellMargin');
        $cellSpacing = ArrayHelper::getValue($this->tableOptions, 'cellSpacing');
        $indent = ArrayHelper::getValue($this->tableOptions, 'indent');
        //Table layout, either fixed or autofit See \PhpOffice\PhpWord\Style\Table for constants.
        $layout = ArrayHelper::getValue($this->tableOptions, 'layout');
        if (is_string($position)) {
            $position = $this->getPositionStyle($position);
        }
        $styles = [
            'alignment' => JcTable::CENTER,
            'bgColor' => '9966CC',
            'borderColor' => '9966CC',
            'borderSize' => 0,
            'cellMargin' => $cellMargin ? Converter::pointToTwip($cellMargin) : 0,
            'cellSpacing' => $cellSpacing ? Converter::pointToTwip($cellSpacing) : null,
            'indent' => $indent,
            'width' => $tableWidth,
            'unit' => $unit,
            'layout' => $layout,
            'position' => $position ?: null,
            'bidiVisual' => null
        ];
        return array_filter($styles, function ($var) {
            return !is_null($var);
        });
    }

    public function filterRowStyles($options = []) {
        if (empty($options)) {
            return null;
        }
        $cantSplit = ArrayHelper::getValue($options, 'cantSplit', false);
        $exactHeight = ArrayHelper::getValue($options, 'exactHeight', false);
        $tblHeader = ArrayHelper::getValue($options, 'tblHeader', false);
        return [
            'cantSplit' => $cantSplit, //. Table row cannot break across pages, true or false.
            'exactHeight' => $exactHeight, //. Row height is exact or at least.
            'tblHeader' => $tblHeader, //. Repeat table row on every new page, true or false.
        ];
    }

    public function mergeStyleArray($styleName, $a, $b, ...$c) {
        $args = func_get_args();
        array_shift($args);
        if (count($args) < 2) {
            throw new \yii\base\InvalidArgumentException('args size min 2');
        }
        $params = [];
        foreach ($args as $array) {
            $temp = $styleName ? ArrayHelper::getValue($array, $styleName) : $array;
            if (is_null($temp)) {
                continue;
            }
            $params[] = (array) $temp;
        }
        if (!count($params)) {
            if ($styleName && $this->hasProperty($styleName)) {
                return $this->$styleName;
            }
            return null;
        }
        if (count($params) < 2) {
            return array_pop($params);
        }
        return call_user_func_array([ArrayHelper::class, 'merge'], $params);
    }

}
